
#include<myMiniEngine.h>
#include"imgui/imgui.h"
#include"myMiniEngine/Core/Timestep.h"
#include <glm/gtc/matrix_transform.hpp>
#include"myMiniEngine/Platform/OpenGL/OpenGLShader.h"
#include"glm/gtc/type_ptr.hpp"
#include"myMiniEngine/Core.h"
#include"myMiniEngine/Renderer/Shader.h"


class ExampleLayer : public myMiniEngine::Layer
{
public:
	ExampleLayer()
		: Layer("Example"),camera(-1.6f, 1.6f, -0.9f, 0.9f),cameraPos(0.0f),squarePos(0.0f)
	{
		vertexArray.reset(myMiniEngine::VertexArray::Create());


		float vertices[3 * 7] = {
			-0.5f, -0.5f, 0.0f, 0.8f, 0.2f, 0.8f, 1.0f,
			 0.5f, -0.5f, 0.0f, 0.2f, 0.3f, 0.8f, 1.0f,
			 0.0f,  0.5f, 0.0f, 0.8f, 0.8f, 0.2f, 1.0f
		};
		myMiniEngine::Ref< myMiniEngine::VertexBuffer> vertexBuffer;
		vertexBuffer.reset(myMiniEngine::VertexBuffer::Create(vertices, sizeof(vertices)));

		myMiniEngine::BufferLayout layout = { {myMiniEngine::ShaderDataType::Float3, "a_Position"},{myMiniEngine::ShaderDataType::Float4, "a_Color"} };
		vertexBuffer->SetLayout(layout);
		vertexArray->AddVertexBuffer(vertexBuffer);


		myMiniEngine::Ref< myMiniEngine::IndexBuffer> indexBuffer;
		unsigned int indices[3] = { 0,1,2 };
		indexBuffer.reset(myMiniEngine::IndexBuffer::Create(indices, sizeof(indices) / sizeof(uint32_t)));
		vertexArray->SetIndexBuffer(indexBuffer);

		m_SquareVA.reset(myMiniEngine::VertexArray::Create());

		float squareVertices[5 * 4] = {
			-0.5f, -0.5f, 0.0f,0.0f,0.0f,
			 0.5f, -0.5f, 0.0f,1.0f,0.0f,
			 0.5f,  0.5f, 0.0f,1.0f,1.0f,
			-0.5f,  0.5f, 0.0f,0.0f,1.0f
		};

		myMiniEngine::Ref<myMiniEngine::VertexBuffer> squareVB;
		squareVB.reset(myMiniEngine::VertexBuffer::Create(squareVertices, sizeof(squareVertices)));
		squareVB->SetLayout({
			{ myMiniEngine::ShaderDataType::Float3, "a_Position" },
			{ myMiniEngine::ShaderDataType::Float2, "a_TexCoord" }
			});
		m_SquareVA->AddVertexBuffer(squareVB);

		uint32_t squareIndices[6] = { 0, 1, 2, 2, 3, 0 };
		myMiniEngine::Ref<myMiniEngine::IndexBuffer> squareIB;
		squareIB.reset(myMiniEngine::IndexBuffer::Create(squareIndices, sizeof(squareIndices) / sizeof(uint32_t)));
		m_SquareVA->SetIndexBuffer(squareIB);

		std::string vertexSrc = R"(
 			#version 330 core
 			
 			layout(location = 0) in vec3 a_Position;
			layout(location = 1) in vec4 a_Color;

			uniform mat4 u_ViewProjection;
			uniform mat4 u_Transform;
 
 			out vec3 v_Position;
			out vec4 v_Color;
 
 			void main()
 			{
 				v_Position = a_Position;
				v_Color=a_Color;
 				gl_Position = u_ViewProjection*u_Transform*vec4(a_Position, 1.0);	
 			}
 		)";

		std::string fragmentSrc = R"(
 			#version 330 core
 			
 			layout(location = 0) out vec4 color;
 
 			in vec3 v_Position;
			in vec4 v_Color;
 
 			void main()
 			{
 				color = vec4(v_Position * 0.5 + 0.5, 1.0);
				color =v_Color;
 			}
 		)";
		shader=myMiniEngine::Shader::Create("VertexColorTriangle",vertexSrc, fragmentSrc);

		std::string flatShaderVertexSrc = R"(
			#version 330 core
			
			layout(location = 0) in vec3 a_Position;

			uniform mat4 u_ViewProjection;
			uniform mat4 u_Transform;

			out vec3 v_Position;

			void main()
			{
				v_Position = a_Position;
				gl_Position = u_ViewProjection*u_Transform*vec4(a_Position, 1.0);	
			}
		)";

		std::string flatColorShaderFragmentSrc = R"(
			#version 330 core
			
			layout(location = 0) out vec4 color;

			in vec3 v_Position;

			uniform vec3 u_Color;

			void main()
			{
				color = vec4(u_Color,1.0f);
			}
		)";

		m_FlatColorShader=myMiniEngine::Shader::Create("FlatColor",flatShaderVertexSrc, flatColorShaderFragmentSrc);


		std::string textureShaderVertexSrc = R"(
 			#version 330 core
 			
 			layout(location = 0) in vec3 a_Position;
 			layout(location = 1) in vec2 a_TexCoord;
 
 			uniform mat4 u_ViewProjection;
 			uniform mat4 u_Transform;
 
 			out vec2 v_TexCoord;
 
 			void main()
 			{
 				v_TexCoord = a_TexCoord;
 				gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0);	
 			}
 		)";
		std::string textureShaderFragmentSrc = R"(
 			#version 330 core
 			
 			layout(location = 0) out vec4 color;
 
 			in vec2 v_TexCoord;
 			
 			uniform sampler2D u_Texture;
 
 			void main()
 			{
 				color = texture(u_Texture, v_TexCoord);
 			}
 		)";

		//textureShader.reset(myMiniEngine::Shader::Create(textureShaderVertexSrc, textureShaderFragmentSrc));
		auto textureShader=shaderLibrary.Load("assets/shaders/Texture.glsl");

		texture=myMiniEngine::Texture2D::Create("assets/textures/Checkerboard.png");
		grassTexture = myMiniEngine::Texture2D::Create("assets/textures/grass.png");


		std::dynamic_pointer_cast<myMiniEngine::OpenGLShader>(textureShader)->Bind();
		std::dynamic_pointer_cast<myMiniEngine::OpenGLShader>(textureShader)->UploadUniformInt("u_Texture", 0);
	}

	void OnUpdate(myMiniEngine::Timestep ts) override
	{
		if (myMiniEngine::Input::IsKeyPressed(MGE_KEY_LEFT))
			cameraPos.x -= cameraMoveSpeed*ts ;
		else if (myMiniEngine::Input::IsKeyPressed(MGE_KEY_RIGHT))
			cameraPos.x += cameraMoveSpeed * ts;

		if (myMiniEngine::Input::IsKeyPressed(MGE_KEY_UP))
			cameraPos.y += cameraMoveSpeed * ts;
		else if (myMiniEngine::Input::IsKeyPressed(MGE_KEY_DOWN))
			cameraPos.y -= cameraMoveSpeed * ts;

		if (myMiniEngine::Input::IsKeyPressed(MGE_KEY_A))
			cameraRotation += cameraRotationSpeed * ts;
		if (myMiniEngine::Input::IsKeyPressed(MGE_KEY_D))
			cameraRotation -= cameraRotationSpeed * ts;


		myMiniEngine::RenderCommand::SetClearColor({ 0.1f, 0.1f, 0.1f, 1 });
		myMiniEngine::RenderCommand::Clear();

		camera.SetPosition(cameraPos);
		camera.SetRotation(cameraRotation);

		myMiniEngine::Renderer::BeginScene(camera);
		
		
		glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(0.1f));
		/*glm::vec4 redcolor(0.8f, 0.2f, 0.3f, 1.0f);
		glm::vec4 bluecolor(0.2f, 0.3f, 0.8f, 1.0f);*/

		std::dynamic_pointer_cast<myMiniEngine::OpenGLShader>(m_FlatColorShader)->Bind();
		std::dynamic_pointer_cast<myMiniEngine::OpenGLShader>(m_FlatColorShader)->UploadUniformFloat3("u_Color",squareColor);

		for (int y = 0; y < 20; y++) {
			for (int i = 0; i < 20; i++) {
				glm::vec3 pos(i * 0.11f, y * 0.11f, 0.0f);
				glm::mat4 transform = glm::translate(glm::mat4(1.0f), pos) * scale;
				myMiniEngine::Renderer::Submit(m_FlatColorShader, m_SquareVA, transform);
			}
		}

		auto textureShader = shaderLibrary.Get("Texture");

		texture->Bind();
		myMiniEngine::Renderer::Submit(textureShader, m_SquareVA, glm::scale(glm::mat4(1.0f), glm::vec3(1.5f)));
		grassTexture->Bind();
		myMiniEngine::Renderer::Submit(textureShader, m_SquareVA, glm::scale(glm::mat4(1.0f), glm::vec3(1.5f)));
		
		//myMiniEngine::Renderer::Submit(shader, vertexArray);

		myMiniEngine::Renderer::EndScene();
	}

	virtual void OnImGuiRender() override
	{
		ImGui::Begin("Setting");
		ImGui::ColorEdit3("SquareColor", glm::value_ptr(squareColor));
		ImGui::End();
	}

	void OnEvent(myMiniEngine::Event& event) override
	{
		
	}
	bool OnKeyPressedEvent(myMiniEngine::KeyPressedEvent& event) {
		
	}

private:
	myMiniEngine::ShaderLibrary shaderLibrary;
	myMiniEngine::Ref<myMiniEngine::Shader> shader;
	myMiniEngine::Ref<myMiniEngine::VertexArray> vertexArray;
	myMiniEngine::Ref<myMiniEngine::Shader> m_FlatColorShader;
	myMiniEngine::Ref<myMiniEngine::VertexArray> m_SquareVA;

	myMiniEngine::Ref<myMiniEngine::Texture2D> texture,grassTexture;


	myMiniEngine::OrthographicCamera camera;
	glm::vec3 cameraPos;

	float cameraMoveSpeed = 5.0f;

	float cameraRotation = 0.0f;
	float cameraRotationSpeed = 180.0f;

	glm::vec3 squarePos;
	float squareMoveSpeed = 1.0f;

	float squareRotation = 0.0f;
	float squareRotationSpeed = 90.0f;

	glm::vec3 squareColor = { 0.2f,0.3f,0.8f };

};



class Sandbox : public myMiniEngine::Application
{
public:
	Sandbox():Application()
	{
		PushLayer(new ExampleLayer());
		
	}

	~Sandbox()
	{

	}


};

myMiniEngine::Application* myMiniEngine::CreateApplication()
{
	return new Sandbox();
}